class XMLFormatter {
    static format(xmlString, options = {}) {
        try {
            const { indent = 2, removeComments = false } = options;
            
            if (!xmlString || typeof xmlString !== 'string') {
                return { success: false, error: '请输入有效的XML内容' };
            }

            xmlString = xmlString.trim();
            if (!xmlString) {
                return { success: false, error: 'XML内容不能为空' };
            }

            // 验证XML格式
            const validationResult = this.validateXML(xmlString);
            if (!validationResult.success) {
                return validationResult;
            }

            // 移除注释（如果需要）
            let processedXml = xmlString;
            if (removeComments) {
                processedXml = processedXml.replace(/<!--[\s\S]*?-->/g, '');
            }

            // 格式化XML
            const formatted = this.formatXMLString(processedXml, indent);
            
            return {
                success: true,
                data: {
                    formatted,
                    original: xmlString,
                    stats: this.getXMLStats(xmlString)
                }
            };
        } catch (error) {
            return { success: false, error: `XML格式化失败: ${error.message}` };
        }
    }

    static minify(xmlString) {
        try {
            if (!xmlString || typeof xmlString !== 'string') {
                return { success: false, error: '请输入有效的XML内容' };
            }

            // 验证XML格式
            const validationResult = this.validateXML(xmlString);
            if (!validationResult.success) {
                return validationResult;
            }

            // 压缩XML：移除不必要的空白字符、换行符和注释
            let minified = xmlString
                .replace(/<!--[\s\S]*?-->/g, '') // 移除注释
                .replace(/>\s+</g, '><') // 移除标签间的空白
                .replace(/\s+/g, ' ') // 多个空白字符压缩为一个
                .replace(/>\s+/g, '>') // 移除标签后的空白
                .replace(/\s+</g, '<') // 移除标签前的空白
                .trim();

            const originalSize = new Blob([xmlString]).size;
            const compressedSize = new Blob([minified]).size;
            const compressionRatio = ((originalSize - compressedSize) / originalSize * 100).toFixed(1);

            return {
                success: true,
                data: {
                    minified,
                    original: xmlString,
                    stats: {
                        originalSize,
                        compressedSize,
                        compressionRatio: `${compressionRatio}%`,
                        spaceSaved: originalSize - compressedSize
                    }
                }
            };
        } catch (error) {
            return { success: false, error: `XML压缩失败: ${error.message}` };
        }
    }

    static validateXML(xmlString) {
        try {
            const parser = new DOMParser();
            const doc = parser.parseFromString(xmlString, 'text/xml');
            
            // 检查解析错误
            const parserError = doc.querySelector('parsererror');
            if (parserError) {
                const errorText = parserError.textContent || parserError.innerText || '';
                return { 
                    success: false, 
                    error: `XML语法错误: ${errorText.replace(/\n/g, ' ').trim()}` 
                };
            }

            // 检查是否为空文档
            if (!doc.documentElement) {
                return { success: false, error: 'XML文档为空或格式无效' };
            }

            return { 
                success: true, 
                data: { 
                    valid: true, 
                    rootElement: doc.documentElement.tagName,
                    message: 'XML格式验证通过'
                } 
            };
        } catch (error) {
            return { success: false, error: `XML验证失败: ${error.message}` };
        }
    }

    static xmlToJson(xmlString) {
        try {
            const validationResult = this.validateXML(xmlString);
            if (!validationResult.success) {
                return validationResult;
            }

            const parser = new DOMParser();
            const doc = parser.parseFromString(xmlString, 'text/xml');
            
            const jsonObj = this.xmlNodeToJson(doc.documentElement);
            const jsonString = JSON.stringify(jsonObj, null, 2);

            return {
                success: true,
                data: {
                    json: jsonString,
                    object: jsonObj,
                    rootElement: doc.documentElement.tagName
                }
            };
        } catch (error) {
            return { success: false, error: `XML转JSON失败: ${error.message}` };
        }
    }

    static xmlNodeToJson(node) {
        const obj = {};
        
        // 处理属性
        if (node.attributes && node.attributes.length > 0) {
            obj['@attributes'] = {};
            for (let i = 0; i < node.attributes.length; i++) {
                const attr = node.attributes[i];
                obj['@attributes'][attr.nodeName] = attr.nodeValue;
            }
        }

        // 处理子节点
        if (node.hasChildNodes()) {
            for (let i = 0; i < node.childNodes.length; i++) {
                const child = node.childNodes[i];
                
                if (child.nodeType === Node.TEXT_NODE) {
                    const text = child.nodeValue.trim();
                    if (text) {
                        if (Object.keys(obj).length === 0 || (Object.keys(obj).length === 1 && obj['@attributes'])) {
                            return text; // 如果只有文本内容，直接返回文本
                        } else {
                            obj['#text'] = text;
                        }
                    }
                } else if (child.nodeType === Node.ELEMENT_NODE) {
                    const childObj = this.xmlNodeToJson(child);
                    
                    if (obj[child.nodeName]) {
                        // 如果已存在同名节点，转换为数组
                        if (!Array.isArray(obj[child.nodeName])) {
                            obj[child.nodeName] = [obj[child.nodeName]];
                        }
                        obj[child.nodeName].push(childObj);
                    } else {
                        obj[child.nodeName] = childObj;
                    }
                }
            }
        }

        return obj;
    }

    static formatXMLString(xmlString, indent = 2) {
        const parser = new DOMParser();
        const doc = parser.parseFromString(xmlString, 'text/xml');
        
        // 处理XML声明
        let result = '';
        if (xmlString.trim().startsWith('<?xml')) {
            const xmlDeclaration = xmlString.match(/<\?xml[^>]+\?>/i);
            if (xmlDeclaration) {
                result += xmlDeclaration[0] + '\n';
            }
        }
        
        result += this.formatXMLNode(doc.documentElement, 0, indent);
        return result;
    }

    static formatXMLNode(node, level = 0, indent = 2) {
        const indentStr = ' '.repeat(level * indent);
        const nextIndentStr = ' '.repeat((level + 1) * indent);
        
        let result = `${indentStr}<${node.nodeName}`;
        
        // 添加属性（每个属性单独一行，如果属性过多）
        if (node.attributes && node.attributes.length > 0) {
            const attributes = Array.from(node.attributes);
            const attributeStr = attributes.map(attr => 
                `${attr.nodeName}="${this.escapeXMLAttribute(attr.nodeValue)}"`
            ).join(' ');
            
            // 如果属性太长，分行显示
            if (attributeStr.length > 60) {
                result += '\n' + attributes.map(attr => 
                    `${indentStr}${' '.repeat(node.nodeName.length + 2)}${attr.nodeName}="${this.escapeXMLAttribute(attr.nodeValue)}"`
                ).join('\n');
            } else {
                result += ` ${attributeStr}`;
            }
        }
        
        // 检查是否有子节点
        const children = Array.from(node.childNodes).filter(child => 
            child.nodeType === Node.ELEMENT_NODE || 
            (child.nodeType === Node.TEXT_NODE && child.nodeValue.trim()) ||
            child.nodeType === Node.COMMENT_NODE
        );
        
        if (children.length === 0) {
            result += ' />';
            return result;
        }
        
        result += '>';
        
        // 如果只有一个文本节点且文本较短，保持在同一行
        if (children.length === 1 && children[0].nodeType === Node.TEXT_NODE) {
            const text = children[0].nodeValue.trim();
            if (text.length <= 50 && !text.includes('\n')) {
                result += this.escapeXMLText(text);
                result += `</${node.nodeName}>`;
                return result;
            }
        }
        
        // 处理多个子节点或复杂内容
        result += '\n';
        
        for (const child of children) {
            if (child.nodeType === Node.ELEMENT_NODE) {
                result += this.formatXMLNode(child, level + 1, indent) + '\n';
            } else if (child.nodeType === Node.TEXT_NODE) {
                const text = child.nodeValue.trim();
                if (text) {
                    // 处理多行文本
                    const lines = text.split('\n').map(line => line.trim()).filter(line => line);
                    for (const line of lines) {
                        result += `${nextIndentStr}${this.escapeXMLText(line)}\n`;
                    }
                }
            } else if (child.nodeType === Node.COMMENT_NODE) {
                const comment = child.nodeValue.trim();
                result += `${nextIndentStr}<!-- ${comment} -->\n`;
            }
        }
        
        result += `${indentStr}</${node.nodeName}>`;
        return result;
    }

    static escapeXMLText(text) {
        return text
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
    }

    static escapeXMLAttribute(text) {
        return text
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&apos;');
    }

    static addSyntaxHighlighting(xmlString) {
        // 添加语法高亮的HTML包装
        let highlighted = xmlString;
        
        // XML声明高亮
        highlighted = highlighted.replace(
            /<\?xml[^>]*\?>/gi,
            '<span class="xml-declaration">$&</span>'
        );
        
        // 注释高亮
        highlighted = highlighted.replace(
            /&lt;!--[\s\S]*?--&gt;/g,
            '<span class="xml-comment">$&</span>'
        );
        
        // 标签高亮 (开始标签、结束标签、自闭合标签)
        highlighted = highlighted.replace(
            /&lt;(\/)?([\w-]+)([^&]*?)(\s*\/?)&gt;/g,
            (match, closing, tagName, attributes, selfClosing) => {
                let result = '&lt;';
                if (closing) result += '<span class="xml-tag-bracket">/</span>';
                result += `<span class="xml-tag-name">${tagName}</span>`;
                
                // 属性高亮
                if (attributes) {
                    result += attributes.replace(
                        /([\w-]+)=(&quot;[^&]*?&quot;|&apos;[^&]*?&apos;)/g,
                        '<span class="xml-attr-name">$1</span>=<span class="xml-attr-value">$2</span>'
                    );
                }
                
                if (selfClosing) result += '<span class="xml-tag-bracket">/</span>';
                result += '&gt;';
                
                return `<span class="xml-tag">${result}</span>`;
            }
        );
        
        return highlighted;
    }

    static getXMLStats(xmlString) {
        try {
            const parser = new DOMParser();
            const doc = parser.parseFromString(xmlString, 'text/xml');
            
            let elementCount = 0;
            let attributeCount = 0;
            let textLength = 0;
            const tagNames = new Set();
            
            const countNodes = (node) => {
                if (node.nodeType === Node.ELEMENT_NODE) {
                    elementCount++;
                    tagNames.add(node.nodeName);
                    
                    if (node.attributes) {
                        attributeCount += node.attributes.length;
                    }
                } else if (node.nodeType === Node.TEXT_NODE) {
                    textLength += node.nodeValue.trim().length;
                }
                
                for (let i = 0; i < node.childNodes.length; i++) {
                    countNodes(node.childNodes[i]);
                }
            };
            
            if (doc.documentElement) {
                countNodes(doc.documentElement);
            }
            
            return {
                elements: elementCount,
                attributes: attributeCount,
                uniqueTags: tagNames.size,
                textLength,
                fileSize: new Blob([xmlString]).size,
                lines: xmlString.split('\n').length
            };
        } catch (error) {
            return {
                elements: 0,
                attributes: 0,
                uniqueTags: 0,
                textLength: 0,
                fileSize: new Blob([xmlString]).size,
                lines: xmlString.split('\n').length
            };
        }
    }
}